﻿using System.Text.RegularExpressions;
using System.Web;
using System.Web.Routing;
using Wisdom.Core;

namespace Wisdom.Web.Mvc
{
    /// <summary>
    /// Defines a class which is used to ensure the URL parameter value must match the provided expression.
    /// </summary>
    public class RegexConstraint : IRouteConstraint
    {
        private readonly Regex expression;
        private readonly bool optional;

        /// <summary>
        /// Initializes a new instance of the <see cref="RegexConstraint"/> class.
        /// </summary>
        /// <param name="expression">The expression.</param>
        public RegexConstraint(string expression)
            : this(expression, false)
        {
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="RegexConstraint"/> class.
        /// </summary>
        /// <param name="expression">The expression.</param>
        /// <param name="optional">if set to <c>true</c> [optional].</param>
        public RegexConstraint(string expression, bool optional)
        {
            Guard.IsNotNull(expression, "expression");

            string pattern = "^(" + expression + ")$";

            this.expression = new Regex(pattern, RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled);
            this.optional = optional;
        }

        /// <summary>
        /// Matches the specified HTTP context.
        /// </summary>
        /// <param name="httpContext">The HTTP context.</param>
        /// <param name="route">The route.</param>
        /// <param name="parameterName">Name of the parameter.</param>
        /// <param name="values">The values.</param>
        /// <param name="routeDirection">The route direction.</param>
        /// <returns></returns>
        public bool Match(HttpContextBase httpContext, Route route, string parameterName, RouteValueDictionary values, RouteDirection routeDirection)
        {
            Guard.IsNotNull(values, "values");

            object value = values[parameterName];

            return value == null ? optional : expression.IsMatch(value.ToString());
        }
    }

}